﻿//--------------------------------------------------------------------------
//
//  File:        KiFUPage.cs
//
//  Coder:       bigeagle@gmail.com
//
//  Date:        2013/2/13
//
//  Description: 打谱页
//  
//  History:     2013/2/13 created by bigeagle  
//
//--------------------------------------------------------------------------

using Bigeagle.Portable.BoardGames;
using Bigeagle.Portable.BoardGames.Go;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// “基本页”项模板在 http://go.microsoft.com/fwlink/?LinkId=234237 上有介绍

namespace EagleGO
{
    /// <summary>
    /// 打谱页窗体
    /// </summary>
    public sealed partial class KiFUPage : EagleGO.Common.LayoutAwarePage
    {
        //Uri _MoveSoundUri;

        static bool IsPlaying = false;
        CancellationTokenSource _CancellationToken ;

        KiFUGame _Game = null;

        KiFUGame _PlayingGame = new KiFUGame();

        List<CommentsMove> _MainGameTreeMoves = null;

        CommentsMove _CurrentMove = null;
        
        /// <summary>
        /// 构造函数
        /// </summary>
        public KiFUPage()
        {
            this.InitializeComponent();
            _MainGameTreeMoves = new List<CommentsMove>();
            _PlayingGame.Moved += _Game_Moved;
            _PlayingGame.StoneRemoved += _Game_StoneRemoved;
            //_MoveSoundUri = new Uri(string.Format("ms-appx:///Sounds/move.wav"));
        }

        ~KiFUPage()
        {
            _PlayingGame.Moved -= _Game_Moved;
            _PlayingGame.StoneRemoved -= _Game_StoneRemoved;
        }
        /// <summary>
        /// 棋局提子事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        async void  _Game_StoneRemoved(object sender, StoneEventArgs e)
        {
            //e.TheStone.IsAlive = false;
            await _Board.Dispatcher.RunAsync(CoreDispatcherPriority.High, async delegate
            {
                //_Board.BindingStones.Remove(e.TheStone);
                //await _Board.RefreshAsync();
                await PlayDeadStoneSound();
            });

        }

        /// <summary>
        /// 棋局走棋事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        async void _Game_Moved(object sender, StoneEventArgs e)
        {
            await _Board.Dispatcher.RunAsync(CoreDispatcherPriority.High, async delegate
                {
                    //_Board.BindingStones.Add(e.TheStone);
                    //await _Board.RefreshAsync();
                    await PlayMoveSound();
                });
        }


        /// <summary>
        /// 使用在导航过程中传递的内容填充页。在从以前的会话
        /// 重新创建页时，也会提供任何已保存状态。
        /// </summary>
        /// <param name="navigationParameter">最初请求此页时传递给
        /// <see cref="Frame.Navigate(Type, Object)"/> 的参数值。
        /// </param>
        /// <param name="pageState">此页在以前会话期间保留的状态
        /// 字典。首次访问页面时为 null。</param>
        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
        }//end method

        /// <summary>
        /// 保留与此页关联的状态，以防挂起应用程序或
        /// 从导航缓存中放弃此页。值必须符合
        /// <see cref="SuspensionManager.SessionState"/> 的序列化要求。
        /// </summary>
        /// <param name="pageState">要使用可序列化状态填充的空字典。</param>
        protected override void SaveState(Dictionary<String, Object> pageState)
        {
        }//end method

        /// <summary>
        /// 导航到本页事件
        /// </summary>
        /// <param name="e"></param>
        protected async override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            this.progressBar.Visibility = Windows.UI.Xaml.Visibility.Visible;
            try
            {
                KiFUItem item = e.Parameter as KiFUItem;
                if (item != null)
                {

                    KiFUGame game = await item.LoadKiFUGameAsync(App.CurrentEncoding);
                    if (game != null)
                    {
                        await BindGame(game);
                        //BindGames(new KiFUGame[] { game });
                    }
                }
            }
            catch (Exception ex)
            {
                Common.Dialog.ShowDialog(ex);
            }
            this.progressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
        }


        private async Task BindGame(KiFUGame game)
        {
            this.gameViewSource.Source = null;
            //this.lvMoves.SelectedItem = null;
            _PlayingGame.Reset();
            //_Board.Reset();
            _Board.GameBoard = _PlayingGame.GameBoard;
            _CurrentMove = null;
            //初始化主线棋局
            _MainGameTreeMoves.Clear();

            //如果是顶层
            if (game.Parent == null)
            {
                _Game = game;
                await SetupPreMoves();
                _MainGameTreeMoves.AddRange(_Game.GetActualPlayMoves());
                _Game.GameInfo.Name = string.IsNullOrEmpty(_Game.GameInfo.Name)
                    ? string.Format("{0} - {1}", _Game.GameInfo.BlackPlayer.ToChineseString()
                    , _Game.GameInfo.WhitePlayer.ToChineseString())
                    : _Game.GameInfo.Name;
                this.DataContext = _Game;
                gameViewSource.Source = new KiFUGame[] { _Game };

            }
            else
            {
            }
            //如果有预置棋子则先放入
            //_PlayingGame = _Game;
            //GoToMove(_CurrentMove);

            RefreshPlayButtonsStatus();
        }

        private async Task SetupPreMoves()
        {
            foreach (Stone stone in _Game.PreMoves)
            {
                //_Board.DrawStone(stone);
                await _Board.RefreshAsync();
            }
        }

        /// <summary>
        /// 棋盘棋子位置点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BoardControl_BoardPositionClicked(object sender, Bigeagle.Metro.Games.Controls.BoardPositionEventArgs e)
        {
            Stone.Sides side = _Game.GetNextSide();
            Stone stone = new Stone();
            stone.X = e.X;
            stone.Y = e.Y;
            stone.Side = side;
            if (_Game.CanDropStone(stone))
            {
                _Game.DropStone(stone);
            }
        }

        /// <summary>
        /// 打谱按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btnKiFU_Tapped(object sender, TappedRoutedEventArgs e)
        {
            //确保应用程序不是处于snap状态
            ApplicationViewState currentState = Windows.UI.ViewManagement.ApplicationView.Value;
            if (currentState == ApplicationViewState.Snapped && !ApplicationView.TryUnsnap())
            {
                return;
            }
            try
            {
                FileOpenPicker openPicker = new FileOpenPicker();
                openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
                openPicker.ViewMode = PickerViewMode.List;
                openPicker.FileTypeFilter.Add(".sgf");

                StorageFile file = await openPicker.PickSingleFileAsync();
                progressBar.Visibility = Windows.UI.Xaml.Visibility.Visible;

                if (file != null)
                {
                    // Application now has read/write access to the picked file
                    IRandomAccessStream istream = await file.OpenAsync(FileAccessMode.Read);
                    Stream stream = istream.AsStreamForRead();
                    byte[] buffer = new byte[stream.Length];
                    int count = await stream.ReadAsync(buffer, 0, buffer.Length);

                    SGFKiFUSerializer serializer = new SGFKiFUSerializer();
                    string sgfString = App.CurrentEncoding.GetString(buffer, 0, buffer.Length);

                    KiFUGame game = serializer.DeSerialize(sgfString);

                    if (game != null)
                    {
                        await BindGame(game);
                    }
                }
            }
            catch (Exception )
            {

            }
            progressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;

        }

        private void btnPlay_Tapped(object sender, TappedRoutedEventArgs e)
        {

        }

        private async void lvMoves_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            CommentsMove move = (CommentsMove)this.lvMoves.SelectedValue;
            if (move != null && _MainGameTreeMoves.Count > 0)
            {
                tbMoveComment.Text = move.Comment;
                RefreshPlayButtonsStatus();
                await GoToMoveAsync(move);
            }
            
        }

        ///// <summary>
        ///// 走到指定的棋步
        ///// </summary>
        ///// <param name="move"></param>
        //private void GoToMove(CommentsMove move)
        //{
        //    //_PlayingGame.Moves.Clear();
        //    //_Board.Reset();
        //    //SetupPreMoves();
        //    _Board.ClearLabels();
        //    List<CommentsMove> moves = _MainGameTreeMoves;
        //    int index = moves.IndexOf(move);
        //    if (index < 0)
        //    {
        //        return;
        //    }
        //    int lastIndex = -1 ;
        //    if(_CurrentMove != null)
        //    {
        //        lastIndex = moves.IndexOf(_CurrentMove) ;
        //    }
        //    //List<CommentsMove> temp = new List<CommentsMove>() ;


        //    if (index >= lastIndex) //如果是往后
        //    {
        //        for (int i = lastIndex + 1; i <= index; i++)
        //            _PlayingGame.DropStone(moves[i]);
        //    }
        //    else   //如果是往前，则移除所有棋子，重新开始
        //    {
        //        //_PlayingGame.Reset();
        //        //_Board.Reset();
        //        //for (int i = 0; i <= index; i++)
        //        //{
        //        //    _PlayingGame.DropStone(moves[i]);
        //        //}
        //        CommentsMove currentMove = (_PlayingGame.MoveController.CurrentCommand as DropStoneCommand)
        //            .DroppedStone as CommentsMove;
        //        while (move != currentMove)
        //        {
        //            _PlayingGame.MoveController.Undo();
        //            currentMove = (_PlayingGame.MoveController.CurrentCommand as DropStoneCommand)
        //                .DroppedStone as CommentsMove;
        //        }


        //    }
        //    if (move.Labels.Count > 0)
        //    {
        //        foreach (KiFUGame.Label label in move.Labels)
        //        {
                    
        //            _Board.DrawLabel(label);
        //        }
        //    }

        //    _CurrentMove = moves[index];
        //    ////删除没有的棋子
        //    //List<Stone> movesToDelete = _PlayingGame.Moves.Where(m => !temp.Contains(m)).ToList();
        //    //foreach (Stone s in movesToDelete)
        //    //{
        //    //    _Board.RemoveStone(s);
        //    //    _PlayingGame.Moves.Remove(s);
        //    //}
        //}


        /// <summary>
        /// 走到指定的棋步
        /// </summary>
        /// <param name="move"></param>
        private async Task GoToMoveAsync(CommentsMove move)
        {
            //_PlayingGame.Moves.Clear();
            //_Board.Reset();
            //SetupPreMoves();
            //await _Board.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
            //    {
            //        _Board.ClearLabels();
            //    });
            List<CommentsMove> moves = _MainGameTreeMoves;
            //_PlayingGame.Moves.Clear();
            int index = moves.IndexOf(move);
            int currentIndex = moves.IndexOf(_CurrentMove);
            if (index < 0)
            {
                return ;
            }
            if (index < currentIndex && currentIndex > 0)
            {
                _PlayingGame.Reset();
                _Board.GameBoard = _PlayingGame.GameBoard;
                for (int i = 0; i <= index; i++)
                {
                    _PlayingGame.DropStone(moves[i]);
                }
            }
            else
            {
                for (int i = currentIndex + 1; i <= index; i++)
                {
                    _PlayingGame.DropStone(moves[i]);
                }
            }

            _CurrentMove = moves[index];
            _Board.CurrentStone = _CurrentMove;
            //_Board.BindingStones.Clear();
            //_Board.BindingStones.AddRange(_PlayingGame.Moves);
            await _Board.RefreshAsync();
        }//end method

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void CollapseButton_Tapped(object sender, TappedRoutedEventArgs e)
        {
            Button button = sender as Button;
            CommentsMove move = button.Tag as CommentsMove;
            await GoToMoveAsync(move);
            List<KiFUGame> games = new List<KiFUGame>();
            for (int i = 1; i < move.ReferenceGame.Count; i++)
            {
                games.Add((KiFUGame)move.ReferenceGame[i]);
                if (string.IsNullOrEmpty(games[i-1].GameInfo.Name))
                {
                    if (games[i-1].Moves.Count > 0)
                    {
                        games[i-1].GameInfo.Name = (games[i-1].Moves[0] as CommentsMove).Name;
                    }
                }
            }
            _MainGameTreeMoves.Clear();
            _MainGameTreeMoves.AddRange(_PlayingGame.Moves.Select(s => s as CommentsMove) );
            _MainGameTreeMoves.AddRange(games[0].Moves.Select(m => m as CommentsMove));
            gameViewSource.Source = games;
            

            //Debug.WriteLine(button.Parent);
        }

        /// <summary>
        /// 自动播放按钮点击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btnAutoPlay_Tapped(object sender, TappedRoutedEventArgs e)
        {
            List<CommentsMove> moves = _MainGameTreeMoves;
            int index = moves.IndexOf(_CurrentMove);
            if (sender == btnAutoPlay)
            {
                if (!IsPlaying)
                {
                    SetButtonsEnabled(btnAutoPlay.Parent as StackPanel, false, btnAutoPlay);
                    IsPlaying = true;
                    this.btnAutoPlay.Content = char.ConvertFromUtf32(0xE103);
                    _CancellationToken = new CancellationTokenSource();
                    try
                    {
                        await Task.Run(async delegate
                            {
                                while (!_CancellationToken.Token.IsCancellationRequested)
                                {
                                    index = moves.IndexOf(_CurrentMove);
                                    if (_CurrentMove != null)
                                    {
                                        if (index < moves.Count - 1)
                                        {
                                            await this.lvMoves.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                                                {
                                                    this.lvMoves.SelectedItem = moves[index + 1];
                                                    this.lvMoves.ScrollIntoView(this.lvMoves.SelectedItem);
                                                    //如果是最后一步则停止
                                                    if (this.lvMoves.SelectedItem == _MainGameTreeMoves.Last())
                                                    {
                                                        _CancellationToken.Cancel();
                                                        IsPlaying = false;
                                                        this.btnAutoPlay.Content = char.ConvertFromUtf32(0xE102);
                                                        RefreshPlayButtonsStatus();

                                                    }
                                                });
                                        }
                                    }
                                    else
                                    {
                                        await this.lvMoves.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                                        {
                                            this.lvMoves.SelectedItem = moves[0];
                                            this.lvMoves.ScrollIntoView(this.lvMoves.SelectedItem);
                                        });
                                    }
                                    await Task.Delay(1000, _CancellationToken.Token);
                                }
                            }, _CancellationToken.Token);
                    }
                    catch (TaskCanceledException)
                    {
                    }
                    RefreshPlayButtonsStatus();
                }
                else
                {
                    _CancellationToken.Cancel();
                    IsPlaying = false;
                    this.btnAutoPlay.Content = char.ConvertFromUtf32(0xE102);
                    RefreshPlayButtonsStatus();
                }
            }
            else if (sender == btnFirst)
            {
                await this.lvMoves.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                {
                    this.lvMoves.SelectedItem = moves[0];
                    this.lvMoves.ScrollIntoView(this.lvMoves.SelectedItem);
                });

            }
            else if (sender == btnPrev)
            {
                if (index > 0)
                {
                    await this.lvMoves.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        this.lvMoves.SelectedItem = moves[index - 1];
                        this.lvMoves.ScrollIntoView(this.lvMoves.SelectedItem);
                    });
                }

            }
            else if (sender == btnNext)
            {
                if (index < moves.Count - 1)
                {
                    await this.lvMoves.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        this.lvMoves.SelectedItem = moves[index + 1];
                        this.lvMoves.ScrollIntoView(this.lvMoves.SelectedItem);
                    });
                }

            }
            else if (sender == btnLast)
            {
                await this.lvMoves.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                {
                    this.lvMoves.SelectedItem = moves[moves.Count - 1];
                    this.lvMoves.ScrollIntoView(this.lvMoves.SelectedItem);
                });

            }
        }

        private void SetButtonsEnabled(StackPanel panel , bool isEnabled, params Button[] exceptButtons)
        {
            foreach (UIElement ui in panel.Children)
            {
                if (ui is Button && exceptButtons.Contains(ui))
                {
                    (ui as Button).IsEnabled = IsEnabled;
                }
            }

        }//end method

        private void RefreshPlayButtonsStatus()
        {
            if (!IsPlaying)
            {
                List<CommentsMove> moves = _MainGameTreeMoves;
                if (_CurrentMove != null)
                {
                    int index = moves.IndexOf(_CurrentMove);
                    btnFirst.IsEnabled = index > 0;
                    btnPrev.IsEnabled = index > 0;
                    btnNext.IsEnabled = index < moves.Count - 1;
                    btnLast.IsEnabled = index < moves.Count - 1;
                }
                else
                {
                    btnFirst.IsEnabled = false;
                    btnPrev.IsEnabled = false;
                    btnNext.IsEnabled = true;
                    btnLast.IsEnabled = true;
                }
            }
            else
            {
                btnFirst.IsEnabled = false;
                btnPrev.IsEnabled = false;
                btnNext.IsEnabled = false;
                btnLast.IsEnabled = false;

            }
            
        }//end method

        private async Task PlayMoveSound()
        {
                //mediaElementMove.Source = uri;
            await mediaElementMove.Dispatcher.RunAsync(CoreDispatcherPriority.High, delegate
            {
                mediaElementMove.Play();
            });
        }

        private async Task PlayDeadStoneSound()
        {
            await mediaElementDeadStone.Dispatcher.RunAsync(CoreDispatcherPriority.High, delegate
            {
                mediaElementDeadStone.Play();
            });
        }

        private async void TextBlock_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
        {
            await Common.Dialog.ShowDialog("double tapped");
        }

        private void BackButton_Tapped(object sender, TappedRoutedEventArgs e)
        {
            Button button = sender as Button;
            KiFUGame currentGame = button.Tag as KiFUGame;
            Common.Dialog.ShowDialog(currentGame);
            if (currentGame.Parent != null)
            {
                gameViewSource.Source = currentGame.Parent.SubGames;
            }
            Debug.WriteLine(button.Tag);
        }

    }//end class
}//end namespace
